package server

import (
	"errors"
	"regexp"
	"sieve_admin_server_userpass/pkg/app"
	"sieve_admin_server_userpass/pkg/config"
	"sieve_admin_server_userpass/pkg/im3/app/api"
	"sieve_admin_server_userpass/pkg/im3/event"
	"sieve_admin_server_userpass/pkg/log"
	"sieve_admin_server_userpass/pkg/timesched"
	"sort"
	"time"
)

var (
	fDid          = config.Int("im.dept", 0, "关联IM部门ID")
	fSyncInterval = config.Int("im.sync.interval", 0, "主动拉取用户数据周期，单位分")
	fSyncSched    = config.String("im.sync.sched", "", "主动拉取用户数据计划时间")
	fAdmin        = config.Ints("server.admin", []int{}, "管理员")
	deptUserList  = []*api.DeptUser{}
	deptUserMap   = map[int]*api.DeptUser{}

	chLoadUsers = make(chan bool)
)

func init() {
	app.Async(loopLoadUsers)
	event.Listen(&event_UsersUpdate{})
	if interval := *fSyncInterval; interval > 0 {
		app.Async(func() {
			for {
				time.Sleep(time.Minute * time.Duration(interval))
				reloadUsers()
			}
		})
	}
	if sched := *fSyncSched; sched != "" {
		if sch, err := timesched.Parse(sched); err != nil {
			log.Err(err)
		} else {
			app.Async(func() {
				sch.Start(func(t time.Time) {
					reloadUsers()
				})
			})
		}
	}
}

type event_UsersUpdate struct{}

func (e *event_UsersUpdate) Handle(from string) {
	reloadUsers()
}

func loopLoadUsers() {
	for <-chLoadUsers {
		if err := loadUsers(); err != nil {
			log.Err(err)
		}
	}
}

func reloadUsers() {
	chLoadUsers <- true
}

func loadUsers() error {
	list, err := api.GetDeptUserList(*fDid)
	if err != nil {
		return err
	}
	deptUserList = list

	m := map[int]*api.DeptUser{}
	for _, u := range list {
		m[u.Uid] = u
		if _, ok := rolePerm[u.Title]; !ok {
			addRole(u.Title)
		}
	}
	deptUserMap = m
	if fn := onLoadUser; fn != nil {
		app.Async(fn)
	}
	return nil
}

var onLoadUser func()

func OnSyncUsers(fn func()) {
	onLoadUser = fn
}

func isAdmin(uid int) bool {
	for _, i := range *fAdmin {
		if uid == i {
			return true
		}
	}
	return false
}

func checkUserPerm(uid int, perm string) bool {
	return true
	if isAdmin(uid) {
		return true
	}
	u, ok := deptUserMap[uid]
	if !ok {
		return false
	}
	perms, ok := rolePerm[u.Title]
	if !ok {
		return false
	}
	return perms[perm]
}

type User struct {
	Uid    int
	Name   string
	Title  string `json:",omitempty"`
	Leader int
}

func (u *User) HasPermission(perm string) bool {
	return checkUserPerm(u.Uid, perm)
}
func (u *User) HasPermissionsOr(perms []string) bool {
	for _, perm := range perms {
		if ok := u.HasPermission(perm); ok {
			return true
		}
	}
	return false
}
func GetUsers() []*User {
	var list []*User
	for _, row := range deptUserList {
		list = append(list, &User{
			Uid:    row.Uid,
			Name:   row.Name,
			Leader: row.Leader,
		})
	}
	return list
}

type UserTreeNode struct {
	User
	Followers []*UserTreeNode
}

func GetUserTree() (*UserTreeNode, error) {
	var tree *UserTreeNode
	m := map[int]*UserTreeNode{}
	for _, du := range deptUserList {
		m[du.Uid] = &UserTreeNode{User: User{Uid: du.Uid, Name: du.Name, Title: du.Title, Leader: du.Leader}, Followers: []*UserTreeNode{}}
	}
	for _, du := range m {
		if du.Leader == 0 {
			if tree != nil {
				return nil, errors.New("部门数据错误：多个负责人")
			}
			tree = du
		} else {
			if l, ok := m[du.Leader]; ok {
				l.Followers = append(l.Followers, du)
			}
		}
	}
	if tree == nil {
		return nil, errors.New("部门数据错误：无负责人")
	}
	tree.Sort()
	return tree, nil
}

func (du *UserTreeNode) Sort() {
	if du.Followers == nil || len(du.Followers) == 0 {
		return
	}
	sort.Slice(du.Followers, func(i, j int) bool {
		return du.Followers[i].Uid < du.Followers[j].Uid
	})
	for _, f := range du.Followers {
		f.Sort()
	}
}

func (du *UserTreeNode) find(uid int) *UserTreeNode {
	if du.Uid == uid {
		return du
	}
	for _, f := range du.Followers {
		if u := f.find(uid); u != nil {
			return u
		}
	}
	return nil
}

func GetUserTreeByLeader(uid int) (*UserTreeNode, error) {
	tree, err := GetUserTree()
	if err != nil {
		return nil, err
	}
	return tree.find(uid), nil
}

func GetUserInfo(uid int) *api.DeptUser {
	u, ok := deptUserMap[uid]
	if !ok {
		return nil
	}
	return u
}

func GetUser(uid int) (map[string]interface{}, error) {
	var (
		Name string
	)
	if err := db.QueryRow("SELECT `Name` FROM `im_allUser` WHERE `Uid`=?", uid).Scan(&Name); err != nil {
		return nil, err
	}
	leader := 0
	role := "超级管理员"
	if uInfo := GetUserInfo(uid); uInfo != nil {
		leader = uInfo.Leader
		reg := regexp.MustCompile(`\(.*?\)|（.*?）`)
		role = reg.ReplaceAllString(uInfo.Title, "")
	}
	var ret = map[string]interface{}{
		"uid":    uid,
		"name":   Name,
		"leader": leader,
		"role":   role,
	}
	return ret, nil
}

func deepLoopUserAuth(tree *UserTreeNode, parentId int, normalPerms, leaderPerms []string) []*User {
	list := []*User{}
	permStatus := false
	leaderUid := 0
	if parentId > 0 {
		if tree.HasPermissionsOr(append(normalPerms, leaderPerms...)) {
			permStatus = true
			if tree.HasPermissionsOr(leaderPerms) {
				parentId = 0
			}
		}
	} else {
		if tree.HasPermissionsOr(leaderPerms) {
			permStatus = true
		}
	}
	if permStatus {
		list = append(list, &User{Uid: tree.Uid, Name: tree.Name, Leader: parentId})
		leaderUid = tree.Uid
	}
	if parentId > 0 {
		leaderUid = parentId
	}
	if len(tree.Followers) > 0 {
		for _, info := range tree.Followers {
			cList := deepLoopUserAuth(info, leaderUid, normalPerms, leaderPerms)
			if len(cList) > 0 {
				list = append(list, cList...)
			}
		}
	}
	return list
}

func GetUserList(ctx *Context, normalPerms, leaderPerms []string) map[string]interface{} {
	ret := make(map[string]interface{})
	// 主管列表
	if ctx.Uid <= 0 {
		return nil
	}
	tree, err := GetUserTree()
	if err != nil {
		return nil
	}
	list := deepLoopUserAuth(tree, 0, normalPerms, leaderPerms)
	userList := []*User{}
	if ctx.HasNotAdminPermissionsOr(normalPerms...) {
		// 读取自己的主管和自己
		parentId := 0
		for _, v := range list {
			if v.Uid == ctx.Uid {
				userList = append(userList, v)
				parentId = v.Leader
				break
			}
		}
		if parentId > 0 {
			for _, v := range list {
				if ctx.Uid == v.Uid {
					continue
				}
				if v.Leader == parentId || v.Uid == parentId {
					userList = append(userList, v)
				}
			}
		}
	} else {
		userList = list
	}
	ret["ProList"] = userList
	ret["AllUserList"] = GetUsers()
	return ret
}
